package com.dyz.gameserver.net.codec;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.dyz.gameserver.commons.message.ClientRequest;
import com.dyz.gameserver.net.MinaMsgHandler;

/**
 * 消息解码器。将连续的字节按照协议规范分割成完整的消息包，并包装成ClientRequest。
 *
 * @author dyz
 */
public class GameMsgDecoder extends CumulativeProtocolDecoder {

    private static final Logger logger = LoggerFactory.getLogger(MinaMsgHandler.class);

    public GameMsgDecoder() {

    }

    /**
     * flag(1 byte)+length(4 byte,后边内容的长度)+protocol code(4 byte)+content
     * length的长度包括  ：消息号+ 内容
     * 解码
     */
    @Override
    protected boolean doDecode(IoSession session, IoBuffer iobuffer,
                               ProtocolDecoderOutput protocolDecoderOutput) throws Exception {
        //	logger.info("iobuffer.remaining()   =   "+iobuffer.remaining());
        //	logger.info("服务端消息的解码");
        synchronized (iobuffer) {
            if (iobuffer.remaining() < (MsgProtocol.flagSize + MsgProtocol.lengthSize + MsgProtocol.msgCodeSize)) {//数据不完整
                //logger.info("数据包长度不足");
                return false;
            }
            iobuffer.mark();
            byte flag = iobuffer.get();//flag，备用
            if (flag == 1) {
                int length = iobuffer.getInt();//读取长度字段
                //System.out.println("消息length："+length+"---"+session.getId());
                if (length <= 0 || length > MsgProtocol.maxPackLength) {//长度字段异常
                    //logger.info("数据包长度异常");
                    return false;
                }
                if (iobuffer.remaining() >= length) {//
                    int preLimit = iobuffer.limit();//记录下当前的limit值

                    /**
                     * 这行代码有一个bug，
                     * 读取协议内容时，如果第一个字节不是1，则越过此字节继续往后的读，直到读到1，
                     * 然而在设置limit时没有考虑到越过去的flag之前的字节，从而导致设置的limit比本应设置的位置小。
                     * 所以导致，iobuffer中当前position到设置的limit的长度小于我们要读取的length。
                     * 结果导致抛出BufferUnderflowException
                     */
                    //iobuffer.limit(MsgProtocol.flagSize+MsgProtocol.lengthSize+length);
                    iobuffer.limit(iobuffer.position() + length);
                    byte[] body = new byte[length];
                    iobuffer.get(body);
                    iobuffer.limit(preLimit);
                    ClientRequest message = new ClientRequest(body);

                    protocolDecoderOutput.write(message);
                    return true;
                } else {
                    //logger.info("数据包尚不完整");
                    iobuffer.reset();
                    return false;
                }
            } else {
                logger.info("flag 错误");
                return false;
            }
        }
    }

    public void finishDecode(IoSession session, ProtocolDecoderOutput out)
            throws Exception {
    }

    public void dispose(IoSession session) throws Exception {
    }
}